package com.hivekion.system.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hivekion.common.core.SystemConstant;
import com.hivekion.common.entity.TreeNode;
import com.hivekion.common.exception.BusinessException;
import com.hivekion.common.redis.RedisUtil;
import com.hivekion.system.domain.SysDept;
import com.hivekion.system.domain.SysUser;
import com.hivekion.system.domain.vo.dept.SysDeptCreateInputVo;
import com.hivekion.system.domain.vo.dept.SysDeptModelVo;
import com.hivekion.system.domain.vo.dept.SysDeptUpdateInputVo;
import com.hivekion.system.domain.vo.dept.SysDeptViewVo;
import com.hivekion.system.mapper.SysDeptMapper;
import com.hivekion.system.service.ISysDeptService;
import com.hivekion.system.service.ISysUserService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class SysDeptServiceImpl extends ServiceImpl<SysDeptMapper, SysDept>
        implements ISysDeptService {
    @Autowired
    ISysUserService userService;
    @Autowired
    private RedisUtil redisUtil;

    @Override
    public Boolean checkDeptNameUnique(String deptName, String deptId) {
        LambdaQueryWrapper<SysDept> deptLambdaQueryWrapper = Wrappers.lambdaQuery();
        deptLambdaQueryWrapper.eq(SysDept::getDeptName, deptName);
        if (StringUtils.isNotEmpty(deptId)) {
            deptLambdaQueryWrapper.ne(SysDept::getId, deptId);
        }
        List<SysDept> list = this.list(deptLambdaQueryWrapper);
        return list.size() > 0;
    }

    @Override
    public boolean create(SysDeptCreateInputVo inputVo) {
        SysDept dept = new SysDept();
        BeanUtils.copyProperties(inputVo, dept);
        if (inputVo.getParentId() == null) {
            dept.setParentId("");
        }
        boolean bl = this.save(dept);
        if (bl) {
            this.updateRedis();
        }
        return bl;
    }

    @Override
    public boolean update(SysDeptUpdateInputVo inputVo) {
        SysDept dept = this.getById(inputVo.getId());
        BeanUtils.copyProperties(inputVo, dept);
        boolean bl = this.save(dept);
        if (bl) {
            this.updateRedis();
        }
        return bl;
    }

    @Override
    public SysDeptModelVo getDeptInfo(String deptId) {
        SysDept dept = this.getById(deptId);
        if (dept == null) {
            throw new BusinessException(500, "未找到部门信息！");
        }
        SysDeptModelVo vo = new SysDeptModelVo();
        BeanUtils.copyProperties(dept, vo);
        return vo;
    }

    @Override
    public boolean delete(String deptId) {
        List<SysDept> children = getChildren(deptId);
        if (children.size() > 0) {
            throw new BusinessException(500, "该部门下还有部门");
        }
        boolean bl = this.removeById(deptId);
        if (bl) {
            this.updateRedis();
        }
        return bl;
    }

    @Override
    public boolean changeStatus(String deptId, Integer status) {
        SysDept dept = this.getById(deptId);
        dept.setStatus(status);
        boolean bl = this.save(dept);
        if (bl) {
            this.updateRedis();
        }
        return bl;
    }

    @Override
    public List<SysDeptViewVo> getList() {
        return buildViewVo(getParentDepts());
    }

    private List<SysDeptViewVo> buildViewVo(List<SysDept> list) {
        List<SysDeptViewVo> nodes = new ArrayList<>();
        if (list != null && list.size() > 0) {
            list.forEach(
                    dept -> {
                        SysDeptViewVo vo = new SysDeptViewVo();
                        BeanUtils.copyProperties(dept, vo);
                        SysUser leaderU = userService.getById(dept.getLeader());
                        if (leaderU != null) {
                            vo.setLeader(leaderU.getUserName());
                        } else {
                            vo.setLeader("-");
                        }
                        vo.setChildren(null);
                        List<SysDeptViewVo> vos = getChilderenVo(dept.getId());
                        if (vos != null && vos.size() > 0) {
                            vo.setChildren(vos);
                        }
                        nodes.add(vo);
                    });
        }
        return nodes;
    }

    private List<SysDeptViewVo> getChilderenVo(String parentId) {
        List<SysDept> list = getChildren(parentId);
        return buildViewVo(list);
    }

    /*
     * redis 缓存数据
     * */
    @Override
    public List<SysDept> getAllList() {
        if (redisUtil.hasKey(SystemConstant.redis_dept_data)) {
            List<SysDept> list =
                    JSON.parseArray(
                            redisUtil.get(SystemConstant.redis_dept_data).toString(),
                            SysDept.class);
            return list;
        } else {
            List<SysDept> allDept = this.list();
            redisUtil.set(SystemConstant.redis_dept_data, JSON.toJSONString(allDept));
            return allDept;
        }
    }

    private void updateRedis() {
        List<SysDept> allDept = this.list();
        redisUtil.set(SystemConstant.redis_dept_data, JSON.toJSONString(allDept));
    }

    @Override
    public List<TreeNode> getTreeSelect() {
        List<TreeNode> treeNodes = buildTreeNode(getParentDepts());
        return treeNodes;
    }

    private List<SysDept> getParentDepts() {
        List<SysDept> parentDepts =
                this.getAllList().stream()
                        .filter(x -> StringUtils.isEmpty(x.getParentId()))
                        .sorted(Comparator.comparing(SysDept::getSortCode))
                        .collect(Collectors.toList());
        return parentDepts;
    }

    private List<TreeNode> buildTreeNode(List<SysDept> list) {
        List<TreeNode> treeNodes = new ArrayList<>();
        if (list != null && list.size() > 0) {
            list.forEach(
                    dept -> {
                        TreeNode node =
                                new TreeNode(dept.getId(), dept.getDeptName(), dept.getId());
                        node.setData(dept);
                        List<TreeNode> children = this.getChildrenNode(dept.getId());
                        if (children != null && children.size() > 0) {
                            node.setLeaf(false);
                            node.setChildren(children);
                        } else {
                            node.setLeaf(true);
                        }
                        treeNodes.add(node);
                    });
        }
        return treeNodes;
    }

    private List<TreeNode> getChildrenNode(String parentId) {
        List<SysDept> list = getChildren(parentId);
        return buildTreeNode(list);
    }

    private List<SysDept> getChildren(String parentId) {
        LambdaQueryWrapper<SysDept> deptLambdaQueryWrapper = Wrappers.lambdaQuery();
        deptLambdaQueryWrapper.eq(SysDept::getParentId, parentId);
        List<SysDept> allList = this.getAllList();
        List<SysDept> list =
                allList.stream()
                        .filter(t -> parentId.equals(t.getParentId()))
                        .sorted(Comparator.comparing(SysDept::getSortCode))
                        .collect(Collectors.toList());
        return list;
    }
}
